package c.x.jy.service.redis;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.api.R;
@SuppressWarnings("all")
public class MemCacheImpl  implements Cache {
	public MemCacheImpl(){
		
	}
	private   Res defaultval = null;

	private   ConcurrentHashMap<String, Long> orderval = new ConcurrentHashMap<String, Long>();
	
	public   ConcurrentHashMap<String, Res> customVal ;

 
	public   Object get(Object key) {
		if (defaultval == null)
			return null;
		return defaultval.getValue(key);

	}
	
	

	/**
	 * 永久有效，只能取一次
	 * 
	 * @param key
	 * @param value
	 */
	public   void put(Object key, Object value) {
		put(key, value, 0);
	}

	/**
	 * 
	 * @param key
	 * @param value
	 * @param time
	 *            时效（秒）
	 */
	public   void put(Object key, Object value, int time) {
		boolean isUpdateTime = true;
		if (time < 1) {
			isUpdateTime = false;
		}

		if (defaultval == null) {
			defaultval = new Res(time, false);
		}
		defaultval.put(key, value, isUpdateTime);

	}

	public   void remove(String key) {
	 
		if(customVal != null&&customVal.containsKey("defalut")) {
			customVal.get("defalut") .remove(key);
		}
	 

	}

	/**
	 * 同步自增
	 */

	public   synchronized Long generateLongKey(String key) {
		Long val = orderval.get(key);
		val = (val == null ? 2l : ++val);
		orderval.put(key, val);
		return val;
	}

	public   Object getObj(String key) {
		if (defaultval == null)
			return null;
		return  deserialize((byte[]) defaultval.getValue(key));
	}

	public   void setObj(String key, Object value, int time) {

		if (defaultval == null) {
			defaultval = new Res(time, false);
		}
		defaultval.put(key,  serialize(value));

	}

	public   Integer getSize(String cache) {
	 if(cache==null||cache.equals("")){
		return  defaultval.getSize( );
	 }
		return customVal.get(cache)==null?0:customVal.get(cache).getSize();
	}
	
 
	@Override
 
	public  void put(String cache, String key, Object value, int time) {
		Res res = null;
		if (customVal == null) {
			customVal = new ConcurrentHashMap<String, Res>();
		}

		if (!customVal.containsKey (cache)) {
			res = new Res(time, false);
			 
		} else {
			res = customVal.get(cache);
			if(time>0){
		    	res.setMaxtime(time);
			} 
		//	System.out.println("time:"+time);
		}
	 
		res.put(key, JSON.toJSONString(value) , true);
	 //	System.out.println("set:"+JSON.toJSONString(res));
		customVal.put(cache, res);
 //	System.out.println("set:"+JSON.toJSONString(customVal));
 
	}

	public   String get(String cache, String key) {
		if (customVal == null || !customVal.containsKey(cache))
			return null;
		Res res = customVal.get(cache);
		if (res == null || !res.containsKey(key))
			return null;
		return   (String) res.getValue(key);
	}
	@Override
	public Object get(String Cache, String key, Class<?> c) {
		// TODO Auto-generated method stub
		String v=get(Cache, key);
		if(StringUtils.isEmpty(v))return null;
		return JSON.parseObject (v,c);
	}
	 
 
	
	
	/**
	 * 序列化
	 * @param object
	 * @return
	 */
    public   byte[] serialize(Object object) {
        if(object==null)return null;
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        byte[] bytes = null;
        try {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            bytes = baos.toByteArray();
        } catch (Exception e) {
            System.err.println("序列化失败" + e.getMessage());
            return null;
        }finally {
        	if(oos!=null)
			try {
				oos.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        	if(baos!=null)
        	try {
				baos.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
        return bytes;
    }
 
    /**
     * 反序列化
     */
    public   Object deserialize(byte[] bytes)  {
            if(bytes==null)return null;
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
        try {
            bais = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bais);
        } catch (Exception e) {
            System.err.println("反序列化失败" + e.getMessage());
            return null;
            
        }finally {
        	if(bais!=null)
        	try {
				bais.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        	if(ois!=null)
        	try {
				ois.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
        try {
			return ois.readObject();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
    }
	
 
 
	@Override
	public void remove(String cache, String key) {
		// TODO Auto-generated method stub
		if (customVal.containsKey (cache)) {
		  Res	res = customVal.get(cache);
			
			if(res.containsKey(key)) {
				res.remove(key);
			}
			 
		}
	}
	@Override
	public String get(String key) {
		 
		// TODO Auto-generated method stub
		return get("defalut", key);
	}
	@Override
	public void set(String key, Object value, Long expire) {
		// TODO Auto-generated method stub
		put("defalut", key, value, expire==null?0:expire.intValue());
	}
	@Override
	public Object get(String key, Class<?> class1) {
		// TODO Auto-generated method stub
	//	System.out.println("getKey:"+get(key));
		Object o= JSON.parseObject(get(key), class1);
		//System.out.println("getKey:"+o);
		return o;
	}



	@Override
	public Set<String> keys(String key) {
		// TODO Auto-generated method stub
		return null;
	}



	@Override
	public void remove(Set<String> keys) {
		for (String string : keys) {
			this.remove(string);
		}
		
	}
 
 

}




class Res implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private int maxtime;
	private long refreshtime;
	private ConcurrentMap<Object, Rc> map =  new ConcurrentHashMap<Object, Rc>();
	private boolean isremove=true;
	
	

	Res(int maxtime) {
		this.maxtime = maxtime;
		refreshtime = System.currentTimeMillis() + (maxtime * 1000);
	};

	
	public Res(int maxtime, boolean b) {
		this.maxtime = maxtime;
		this.refreshtime = System.currentTimeMillis() + (maxtime * 1000);
		this.isremove=b;
	}

	public boolean containsKey(String key) {
		return map.containsKey(key);
	}
	public void setMaxtime(int maxtime){
		this.maxtime=maxtime;
		if(this.refreshtime >0&&this.refreshtime >System.currentTimeMillis() + (maxtime * 1000))
		this.refreshtime = System.currentTimeMillis() + (maxtime * 1000);
	}
	
	public void refresh() {
		long t = System.currentTimeMillis();
		if (refreshtime < t) {
			// System.out.println("缓存长度："+map);
			refreshtime = System.currentTimeMillis() + (maxtime * 1000);
			Iterator<Entry<Object, Rc>> it = map.entrySet().iterator();
			while (it.hasNext()) {
				Entry<Object, Rc> m = it.next();
				Rc r = (Rc) m.getValue();
				if (r.getMaxtime() < t) {
					it.remove();
				}else if(refreshtime>r.getMaxtime()){
					refreshtime=r.getMaxtime();
				}
			}
			
		}

	}


	public boolean isEmpty(){
	 
		return map.isEmpty();
	}
	public int size(){
		refresh();
		return map.size();
	}
	
	public void put(Object key, Object value) {
 
		
		put(key, value, true);
	}
	/**
	 * 
	 * @param key
	 * @param value
	 * @param isUpdateTime 更新后是否删除
	 */
	public void put(Object key, Object value,boolean isUpdateTime) {
		refresh();
		Rc r = new Rc();
	 
		if(isUpdateTime)r.setMaxtime(System.currentTimeMillis() + (maxtime * 1000));
		r.setObject(value);
	
		map.put(key, r);
	}

	public Object getValue(Object key) {
		refresh();
		
		if(map.isEmpty())return null;
		Rc r = (Rc) map.get(key);
		if(r==null)return null;
		Object o = r.getObject();
		if(isremove)map.remove(key);
		return o;
	}
	public void remove(String key){
		Rc r = new Rc();
		r.setMaxtime(System.currentTimeMillis() -1);
		map.put(key, r);
	}

	public int getSize( ) {
		refresh();
	//	System.out.println(JSON.toJSONString(map));
		return map.size();
	}
}

class Rc implements Serializable{

   /**
* 
*/
private static final long serialVersionUID = 3186443177690614339L;

	private String id;
   
	private long maxtime;
	private Object object;
	
	
	
	public String getId() {
		return id;
	}
 
	public void setId(String id) {
		this.id = id;
	}
	public long getMaxtime() {
		return maxtime;
	}
	public void setMaxtime(long maxtime) {
		this.maxtime = maxtime;
	}
	public Object getObject() {
		return object;
	}
	public void setObject(Object object) {
		this.object = object;
	}
	
	
	@Override
	public String toString() {
		return "R [id=" + id + ", maxtime=" + maxtime + ", object=" + object + "]";
	}
	@Override
	    public boolean equals(Object obj) {
	       if(this == obj)
	           return true;
	       
	       if(obj == null)
	           return false;
	       if(!(obj instanceof R))
	           return false;
	       Rc other = (Rc)obj;
	       if(this.id == null||other.id ==null){
	    	   return false;
	       }else if(!this.id.equals(other.id))
	           return false;
	   
	       return true;
	    }
	

}

